home *** CD-ROM | disk | FTP | other *** search
- // MIOTDREM - Execution support
- // ----------------------------
- //
- // Copyright (c) 1991, Stuart G. Phillips. All rights reserved.
- //
- // Permission is granted for non-commercial use of this software.
- // You are expressly prohibited from selling this software in any form,
- // distributing it with another product, or removing this notice.
- // THIS SOFTWARE IS PROVIDED ``AS IS'' AND WITHOUT ANY EXPRESS OR
- // IMPLIED WARRANTIES, INCLUDING, WITHOUT LIMITATION, THE IMPLIED
- // WARRANTIES OF MERCHANTIBILITY AND FITNESS FOR A PARTICULAR
- // PURPOSE.
- //
- // This module contains the execution support routines for MIOTDREM.
- // The routines deal with the machine level of the V40 such as handling
- // breakpoint and other interrupts, reading and writing registers, and
- // controlling program execution
- //
- //
-
- // Make sure compiler invokes TASM to assemble our inline code
-
- #pragma inline
-
- #include "miotdr.h"
- #include "mio.h"
-
- // Static procedure templates
-
- static int mc_run();
-
-
- // Local storage for CPU state
-
- struct cpu cpu = { {0,0,0,0,0,0,0,0} , // EAX, EBX, ECX, EDX
- 0x00f0, 0, // SP, ESP
- 0,0,0,0,0,0, // EBP, ESI, EDI
- {0}, // Flags
- 0x100, 0, // IP, CS
- 0,0,0,0,0 // DS, SS, ES, FS, GS
- };
-
- void read_regs()
- {
- send((unsigned char *)&cpu,sizeof(struct cpu));
- }
-
-
- void write_regs(struct cpu *regs)
- {
- unsigned char *s = (unsigned char *) regs;
- unsigned char *d = (unsigned char *) &cpu;
-
- for (int i = 0;i < sizeof(struct cpu);i++)
- *d++ = *s++;
-
- send_ack();
- }
-
-
- int go_program()
- {
- return(mc_run());
- }
-
-
-
- // Machine assist procedures
- // =========================
- //
- // The following low level procedures provide the context switching
- // between MIOTDREM and the program under test.
- //
-
-
- // Local storage for MIOTDREM stack on context switch
-
- static unsigned int saved_ss, saved_sp;
-
-
- // mc_run()
- //
- // This procedure transfers control to the program under test according
- // to the registers saved in struct cpu cpu. A return from the program
- // under test to MIOTDREM occurs whenever a breakpoint is hit, a single
- // step cycle is executed or a STOP message is received over the serial
- // link. In all cases control is passed back to MIOTDREM by simulating
- // a return from mc_run() as invoked in go_program() above.
- //
- // The return code in AX is used to determine what caused control to be
- // returned to MIOTDREM. The value is passed back to TD by tdrproc().
-
- static int mc_run()
- {
- // For now - set the three interrupt vectors each time we run
- // the program under test
-
- setvect(0x00,(void interrupt(far *)())mc_brk0);
- setvect(0x01,(void interrupt(far *)())mc_brk1);
- setvect(0x03,(void interrupt(far *)())mc_brk3);
-
- // Push our local machine state onto MIOTDREM stack for later
- // recovery and save our stack (S.O.S)
-
- asm { push es;
- pushf;
- mov saved_ss,ss;
- mov saved_sp,sp;
- };
-
- // Start restoring the registers for the program under test
-
- asm { mov ax,word ptr cpu.g_regs.w.uax;
- mov bx,word ptr cpu.g_regs.w.ubx;
- mov cx,word ptr cpu.g_regs.w.ucx;
- mov dx,word ptr cpu.g_regs.w.udx;
- mov si,word ptr cpu.usi;
- mov di,word ptr cpu.udi;
- mov bp,word ptr cpu.ubp;
- mov es,word ptr cpu.ues;
-
- cli; // Disable interrupts
- mov ss,word ptr cpu.uss;
- mov sp,word ptr cpu.usp;
- sti;
-
- push word ptr cpu.flags;
- push word ptr cpu.segment;
- push word ptr cpu.offset; // Values pushed for iret
-
- mov ds,word ptr cpu.uds;
- iret; // Return to program under test
- };
- return(0); // Keep the compiler happy
- }
-
-
- void mc_return()
- {
- // Discard the pushed registers created by the entry code
-
- asm { pop di;
- pop si;
- pop bp;
- };
-
- // Save original DS and DX, then restore our local DGROUP
-
- asm { push dx;
- push ds;
- mov dx,DGROUP;
- mov ds,dx;
- };
-
- // Save state in local struct cpu cpu
-
- asm { mov word ptr cpu.udi,di;
- mov word ptr cpu.usi,si;
- pop word ptr cpu.uds;
- mov word ptr cpu.ues,es;
- pop word ptr cpu.g_regs.w.udx;
-
- // Discard return from mc_return()
-
- pop dx; // *JUNK*
- pop dx; // *JUNK*
-
- mov word ptr cpu.g_regs.w.ucx,cx;
- mov word ptr cpu.g_regs.w.ubx,bx;
- pop word ptr cpu.g_regs.w.uax;
- pop word ptr cpu.ubp;
-
- pop word ptr cpu.offset;
- pop word ptr cpu.segment;
- pop word ptr cpu.flags;
-
- };
-
- // Save current stack and swap back to MIOTDREM local stack
-
- asm { mov word ptr cpu.uss,ss;
- mov word ptr cpu.usp,sp;
-
- cli; // Disable interrupts
- mov ss,word ptr saved_ss;
- mov sp,word ptr saved_sp;
- sti;
-
- // AX contains the reason for return
- // Restore registers pushed on the stack by mc_run() explicitly
-
- popf;
- pop es;
-
- // Registers pushed on the stack by entry to mc_run() are
- // restored by our exit code
- };
- }
-
-
- // mc_brk3()
- //
- // This procedure us the interrupt handler for breakpoint instructions.
- // It calls mc_return() to transfer control from the program under test
- // back to MIOTDREM
-
- void mc_brk3()
- {
- asm { push ax; // Save AX
- mov ax,TD_BRK3; // Reason for return
- };
-
- mc_return();
- }
-
- // mc_brk1()
- //
- // This procedure is the interrupt handler for single step instructions.
- // It calls mc_return() to transfer control from the program under test
- // back to MIOTDREM
- //
-
-
- void mc_brk1()
- {
- asm { push ax; // Save AX
- mov ax,TD_BRK1; // Reason for return
- };
-
- mc_return();
- }
-
-
-
- // mc_brk0()
- //
- // This procedure is the interrupt handler for divide by zero interrupts.
- // It calls mc_return() to transfer control from the program under test
- // back to MIOTDREM
-
- void mc_brk0()
- {
- asm { push ax; // Save AX
- mov ax,TD_BRK0; // Reason for return
- };
-
- mc_return();
- }
-
-
- // mc_stop()
- //
- // This procedure is invoked from the serial link interrupt handler if
- // a stop packet is detected. We clean up the stack from the previous
- // serial link interrupt and save the state of the program under test
- // as it was when the serial link interrupt occurred. Control is then
- // transferred back to MIOTDREM.
- //
-
-
- void mc_stop()
- {
- // We're not going to return to our caller (scc_int) - the return from
- // this routine is made to look like a return from mc_run().
-
- // Firstly undo the effects of the call that got us here
-
- asm { pop di; // Restore pushed registers
- pop si;
- pop bp;
- mov sp,bp; // Collapse the stack frame belonging
- // to scc_int. This also junks the
- // return from mc_stop.
- };
-
- // The stack now looks like it did on entry to scc_int().
- // Save state in local struct cpu cpu by pop'ing the stack
-
- asm { pop word ptr cpu.ubp;
- pop word ptr cpu.udi;
- pop word ptr cpu.usi;
- pop word ptr cpu.uds;
- pop word ptr cpu.ues;
- pop word ptr cpu.g_regs.w.udx;
- pop word ptr cpu.g_regs.w.ucx;
- pop word ptr cpu.g_regs.w.ubx;
- pop word ptr cpu.g_regs.w.uax;
- pop word ptr cpu.offset;
- pop word ptr cpu.segment;
- pop word ptr cpu.flags;
- };
-
- // Save current stack and swap back to MIOTDREM local stack
-
- asm { mov word ptr cpu.uss,ss;
- mov word ptr cpu.usp,sp;
-
- cli; // Disable interrupts
- mov ss,word ptr saved_ss;
- mov sp,word ptr saved_sp;
- sti;
-
- mov ax,TD_KEYINTR; // Why we returned as return code
-
- // Restore registers pushed on the stack by mc_run() explicitly
-
- popf;
- pop es;
-
- // Registers pushed on the stack by entry to mc_run() are
- // restored by our exit code
- };
- }
-